package org.ricks.net.action.parser;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

public enum ProtocolParserEnum {

    STRING {
        private final StringProtocolParser parser = new StringProtocolParser();

        @Override
        public ProtocolParser getParser() {
            return parser;
        }
    },

    PROTOBUF {
        private final ProtobufProtocolParser parser = new ProtobufProtocolParser();

        @Override
        public ProtocolParser getParser() {
            return parser;
        }
    },

    JSON_JACKSON {
        private ProtocolParser parser;

        @Override
        public ProtocolParser getParser() {
            if (Objects.isNull(parser)) parser = new JsonProtocolParser("jackson");
            return parser;
        }
    },

    JSON_GSON {
        private JsonProtocolParser parser;

        @Override
        public ProtocolParser getParser() {
            if (Objects.isNull(parser)) parser = new JsonProtocolParser("gson");
            return parser;
        }
    },

    JSON_FASTJSON {
        private JsonProtocolParser parser;

        @Override
        public ProtocolParser getParser() {
            if (Objects.isNull(parser)) parser = new JsonProtocolParser("fastjson");
            return parser;
        }
    };

    public abstract ProtocolParser getParser();


    private static class StringProtocolParser implements ProtocolParser {
        private final Charset charset;

        public StringProtocolParser() {
            this(StandardCharsets.UTF_8);
        }

        public StringProtocolParser(Charset charset) {
            this.charset = charset;
        }

        @Override
        public <T> T deserialize(byte[] data, Type type) throws IOException {
            // 新增：支持 Object 类型作为字符串处理
            if (type == String.class || type == CharSequence.class || type == Object.class) {
                return (T) new String(data, charset);
            }

            // 支持 TypeReference 的泛型解析
            if (type instanceof ParameterizedType parameterizedType) {
                Type rawType = parameterizedType.getRawType();
                if (rawType == String.class || rawType == Object.class) {
                    return (T) new String(data, charset);
                }
            }

            throw new IllegalArgumentException("Unsupported type: " + type);
        }

        @Override
        public byte[] serialize(Object object) {
            if (object instanceof String str) {
                return str.getBytes(charset);  // 字符串转字节[7](@ref)
            }
            return object.toString().getBytes(charset);
        }
    }

    private static class ProtobufProtocolParser implements ProtocolParser {

        // 缓存反射方法 (Class -> Method)
        private static final Map<Class<?>, Method> PARSER_METHOD_CACHE = new ConcurrentHashMap<>();
        private static final Map<Class<?>, Method> PARSE_FROM_METHOD_CACHE = new ConcurrentHashMap<>();
        private static final String PARSE_FROM_METHOD = "parseFrom";
        private static final String PARSER_METHOD = "parser";
        private static final String TO_BYTE_ARRAY_METHOD = "toByteArray";

        @Override
        public <T> T deserialize(byte[] data, Type type) throws IOException {
            if (!(type instanceof Class<?> clazz)) {
                throw new IllegalArgumentException("Protobuf deserialization requires Class type");
            }

            try {
                // 获取或缓存parser方法
                Method parserMethod = PARSER_METHOD_CACHE.computeIfAbsent(clazz, cls -> getMethod(cls, PARSER_METHOD));

                // 获取parser实例
                Object parser = parserMethod.invoke(null);

                // 获取或缓存parseFrom方法
                Method parseFromMethod = PARSE_FROM_METHOD_CACHE.computeIfAbsent(clazz, cls -> getMethod(parser.getClass(), PARSE_FROM_METHOD, byte[].class));

                // 执行反序列化
                @SuppressWarnings("unchecked")
                T result = (T) parseFromMethod.invoke(parser, data);
                return result;
            } catch (InvocationTargetException | IllegalAccessException e) {
                throw new IOException("Protobuf deserialization failed for " + clazz.getName(), e);
            }
        }

        @Override
        public byte[] serialize(Object object) throws IOException {
            try {
                // 动态调用toByteArray()
                Method method = object.getClass().getMethod(TO_BYTE_ARRAY_METHOD);
                return (byte[]) method.invoke(object);
            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                throw new IOException("Protobuf serialization failed", e);
            }
        }

        // 安全获取反射方法
        private Method getMethod(Class<?> clazz, String name, Class<?>... paramTypes) {
            try {
                return clazz.getMethod(name, paramTypes);
            } catch (NoSuchMethodException e) {
                throw new IllegalArgumentException("Missing required method: " + clazz.getName() + "." + name, e);
            }
        }
    }


    private static class JsonProtocolParser implements ProtocolParser {
        // JSON 库适配器缓存 (库名 -> 序列化/反序列化方法)
        private static final Map<String, JsonProtocolParser.JsonAdapter> ADAPTER_CACHE = new ConcurrentHashMap<>();
        private final JsonProtocolParser.JsonAdapter adapter;

        public JsonProtocolParser(String libName) {
            this.adapter = ADAPTER_CACHE.computeIfAbsent(libName, this::initAdapter);
        }

        @Override
        public <T> T deserialize(byte[] data, Type type) throws IOException {
            try {
                return adapter.deserialize(new String(data), type);
            } catch (Exception e) {
                throw new IOException("JSON deserialization failed", e);
            }
        }

        @Override
        public byte[] serialize(Object object) throws IOException {
            try {
                return adapter.serialize(object).getBytes();
            } catch (Exception e) {
                throw new IOException("JSON serialization failed", e);
            }
        }

        // 初始化 JSON 库适配器
        private JsonProtocolParser.JsonAdapter initAdapter(String libName) {
            return switch (libName.toLowerCase()) {
                case "jackson" -> new JsonProtocolParser.JacksonAdapter();
                case "gson" -> new JsonProtocolParser.GsonAdapter();
                case "fastjson" -> new JsonProtocolParser.FastJsonAdapter();
                default -> throw new IllegalArgumentException("Unsupported JSON library: " + libName);
            };
        }

        // JSON 适配器接口
        interface JsonAdapter {
            <T> T deserialize(String json, Type type) throws Exception;
            String serialize(Object obj) throws Exception;
        }

        // Jackson 实现[8](@ref)[9](@ref)
        static class JacksonAdapter implements JsonProtocolParser.JsonAdapter {
            private final Object mapper;
            private final Method readValue;
            private final Method writeValue;

            public JacksonAdapter() {
                try {
                    Class<?> mapperClass = Class.forName("com.fasterxml.jackson.databind.ObjectMapper");
                    this.mapper = mapperClass.getDeclaredConstructor().newInstance();
                    this.readValue = mapperClass.getMethod("readValue", String.class, Class.class);
                    this.writeValue = mapperClass.getMethod("writeValueAsString", Object.class);
                } catch (Exception e) {
                    throw new RuntimeException("Jackson initialization failed", e);
                }
            }

            @Override
            public <T> T deserialize(String json, Type type) throws Exception {
                return (T) readValue.invoke(mapper, json, type);
            }

            @Override
            public String serialize(Object obj) throws Exception {
                return (String) writeValue.invoke(mapper, obj);
            }
        }

        // Gson 实现[11](@ref)[13](@ref)
        static class GsonAdapter implements JsonProtocolParser.JsonAdapter {
            private final Object gson;
            private final Method fromJson;
            private final Method toJson;

            public GsonAdapter() {
                try {
                    Class<?> gsonClass = Class.forName("com.google.gson.Gson");
                    this.gson = gsonClass.getDeclaredConstructor().newInstance();
                    this.fromJson = gsonClass.getMethod("fromJson", String.class, Class.class);
                    this.toJson = gsonClass.getMethod("toJson", Object.class);
                } catch (Exception e) {
                    throw new RuntimeException("Gson initialization failed", e);
                }
            }

            @Override
            public <T> T deserialize(String json, Type type) throws Exception {
                return (T) fromJson.invoke(gson, json, type);
            }

            @Override
            public String serialize(Object obj) throws Exception {
                return (String) toJson.invoke(gson, obj);
            }
        }

        // Fastjson 实现[6](@ref)
        static class FastJsonAdapter implements JsonProtocolParser.JsonAdapter {
            private final Method parseObject;
            private final Method toJSONString;

            public FastJsonAdapter() {
                try {
                    Class<?> jsonClass = Class.forName("com.alibaba.fastjson.JSON");
                    this.parseObject = jsonClass.getMethod("parseObject", String.class, Class.class);
                    this.toJSONString = jsonClass.getMethod("toJSONString", Object.class);
                } catch (Exception e) {
                    throw new RuntimeException("Fastjson initialization failed", e);
                }
            }

            @Override
            public <T> T deserialize(String json, Type type) throws Exception {
                return (T) parseObject.invoke(null, json, type);
            }

            @Override
            public String serialize(Object obj) throws Exception {
                return (String) toJSONString.invoke(null, obj);
            }
        }
    }


}
